<?php
//9位长度订单号的几种方案:

function right(string $str, int $len) {
    if (strlen($str) <= $len) {
        return $str;
    }
    else {
        return substr($str, strlen($str) - $len);
    }
}

$seq = 12;
$ts = time();
$ts = strtotime('2037-8-18 15:5');

////# 方案1:
////年份2位数字;
////一年中的第几天：最大366, 共3位;
////每天的订单序号, 4位。 共9位数【限制每天最多9,999】
////比如： 22195 0003
////公式: date('y', $ts) . right('00' . date('z', $ts), 3) . $seq4
//$seq4 = right('0000' . $seq, 4);
//$order_id = date('y', $ts) . '-' . right('00' . date('z', $ts), 3) . '-' . $seq4;
//echo '方案1: ' . $order_id . PHP_EOL;

//# 方案2:
//自2020年以来的天数 (ts - ts%86400)/86400, 共5位数.
//每天的订单序号, 4位。 共9位数【限制每天最多9,999】
//例如: 19349 0003
//公式: right('0000' . (($ts - $ts % 86400)/86400), 5) . $seq4

////# 方案2调整1:
////自2019年以来的天数 (ts - ts%86400)/86400, 共4位数, 可用27年(但是要去掉从1000开始的3年)
////每天的订单序号, 5位。 共9位数【限制每天最多99,999】
////例如: 19349 00003
////公式: right('0000' . (($ts - $ts % 86400)/86400), 5) . $seq4
//$ts_from = strtotime('2019-1-1');
//$seq5 = right('0000' . $seq, 5);
//$order_id = right('0000' . (($ts - $ts_from - ($ts - $ts_from) % 86400) / 86400), 4) . '-' . $seq5;
//echo '方案2(调整1): ' . $order_id . PHP_EOL;

////# 方案2调整2:
////自2019年以来的天数 (ts - ts%86400)/86400, 共4位数, 可用27年(但是要去掉从1000开始的3年)
////当前天的秒数, 5位。 共9位数【限制每秒最多1】
////例如: 19349 12345
////公式: right('0000' . (($ts - $ts % 86400)/86400), 5) . $seq4
//$ts_from = strtotime('2019-1-1');
//$seq5 = right('0000' . ($ts % 86400), 5);
//$order_id = right('0000' . (($ts - $ts_from - ($ts - $ts_from) % 86400) / 86400), 4) . '-' . $seq5;
//echo '方案2(调整2): ' . $order_id . PHP_EOL;

//# 方案2调整3:
//自2019年以来的天数 (ts - ts%86400)/86400, 共4位数, 可用27年(但是要去掉从1000开始的3年)
//当前天的秒数除以100 + 当前100秒内的订单序号, 3+2位。 共9位数【限制每100秒最多99】 ==> 这种最合适
//例如: 19349 12345
//公式: right('0000' . (($ts - $ts % 86400)/86400), 3)/100 . $seq3 . $seq_period
$ts_from = strtotime('2022-1-1'); // 如果是从0开始, 则天数会达到5位数
//当前秒
$seq3 = right('0000' . (int)(($ts % 86400) / 100), 3);
//echo $seq4 . PHP_EOL;
$seq_period = '66';//每100秒最多99个订单
$order_id = right('0000' . (($ts - $ts_from - ($ts - $ts_from) % 86400) / 86400), 4) . '-' . $seq3 . '-' . $seq_period;
echo '方案2(调整3): ' . $order_id . PHP_EOL;

////# 方案3
////yymmdd + 3位序号。   共9位数, 【限制每天最多1,000】
////比如: 220818 003
////公式: date('ymd', $ts) . $seq3
//$seq3 = right('0000' . $seq, 3);
//$order_id = date('ymd', $ts) . '-' . $seq3;
//echo '方案3: ' . $order_id . PHP_EOL;

////# 方案4
////年份2位数字;
////当前时间的自今年以来的小时数: 366 * 24 + 23 = 8784+23, 共4位;
////将每小时分10份, 当前时间在第几份, 0~9, 共1位;
////当前订单号序数, 2位。共9位数, 【限制每6分钟最多99, 相当于每天最多999】
////公式: date('y', $ts) . right('0000' .(date('z', $ts) * 24  + date('H')), 5) . $seq2
//$seq2 = right('0000' . $seq, 2);
//$hour_id = (int)(date('i', $ts) / 10);
//$order_id = date('y', $ts) . '-' . right('0000' . (date('z', $ts) * 24 + date('H')), 4) . '-' . $hour_id . '-' . $seq2;
//echo '方案4: ' . $order_id . PHP_EOL;

/**
 * 长(整形)订单号转为短(字符串, 0-9a-z,不含字母i和o)订单号
 * @param int $orderId 长整型订单号
 * @return string 大写的34进制字符串
 */
function orderIdToShortOrderId(int $orderId) {
    //十进制到任意进制转换: 除以进制数, 直到商为0, 然后把余数顺序反过来.
    $jinzhi = 34;
    $orderId2 = $orderId;
    $arrChar = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];//不含字母i和o
    $arrRemainder = [];//余数
    while ($orderId > 0) {
        $shang = floor($orderId / $jinzhi);//商
        $remainder = $orderId % $jinzhi;//余数
        $arrRemainder[] = $remainder;
        $orderId = $shang;
    }
    $arr = array_reverse($arrRemainder);
    $arrId = [];
    foreach ($arr as $value) {
        $arrId[] = $arrChar[$value];
    }
    $shortOrderId = strtoupper(implode('', $arrId));
    return $shortOrderId;
}

/**
 * 短(字符串)订单号转为长(整形)订单号
 * @param string $shortOrderId
 * @return int 长整型订单号
 */
function shortOrderIdToOrderId(string $shortOrderId) {
    $jinzhi = 34;
    $shortOrderId = strtolower($shortOrderId);
    $arrChar = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];//不含字母i和o
    $arrCharSeq = array_flip($arrChar);//交换键值对
    $shortOrderId2 = strrev($shortOrderId);//反转
    $rt = 0;
    for ($i = 0, $n = mb_strlen($shortOrderId2); $i < $n; $i++) {
        $value = mb_substr($shortOrderId2, $i, 1);
        if (!array_key_exists($value, $arrCharSeq)) {
            return 0;
        }
        $remainder = $arrCharSeq[$value];
        $rt += pow($jinzhi, $i) * $remainder;
    }
    return $rt;
}

$arr = [
    //1661918217,
    //1661918218,
    570825566,//9位 => 6,  2037/8/13, CK5BR8
    132525566,//9位 => 6, 2X5TGS
    402525566,//9位 => 6, 8V7BH8
    680425566,//9位 => 6,  2037/8/18, EZ5VEN
    4978255066,//10位 => 7,  2032/8/18, 37KA90N
    6804255001,//10位 => 7,  2037/8/18, 4DRQMR3
    1325255066,//10位 => 6, V5Q2E6
    2132525566,//10位 => 7, 1CXT7A6
    //5132525566,
    //9132525566,
    //11325255001,
    //11325255066,
    //11325255966,
    //51325255001,
    //51325255066,
    //51325255966,//Z7MF8BY
];
//注意: 超过525亿就会达到8位

foreach ($arr as $orderId) {
    $shortOrderId = orderIdToShortOrderId($orderId);
    $id = shortOrderIdToOrderId($shortOrderId);
    echo number_format($orderId) . ' => ' . $shortOrderId . ', ' . strlen($shortOrderId) . ' => ' . $id . PHP_EOL;
}
$time = time() + 8 * 3600;
$rt = $time % 86400;
//$key = $time - $rt % 100;
$key = $time - $time % 100;
echo $time . ' => ' . $rt . '=> ' . $key . PHP_EOL;

